package org.xxx.epms.result.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.xxx.epms.result.dto.*;
import org.xxx.epms.result.feign.*;
import org.xxx.epms.result.mapper.AqiMeasuredResultMapper;
import org.xxx.epms.result.mapper.GridCityMapper;
import org.xxx.epms.result.mapper.GridProvinceMapper;
import org.xxx.epms.result.models.AqiGrade;
import org.xxx.epms.result.models.AqiMeasuredResult;
import org.xxx.epms.result.models.GridProvince;
import org.xxx.epms.result.service.AqiGradeService;
import org.xxx.epms.result.service.AqiMeasuredResultService;
import org.xxx.epms.result.service.GridCityService;
import org.xxx.epms.result.service.GridProvinceService;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.IntStream;

@Service
public class AqiMeasuredResultServiceImpl extends ServiceImpl<AqiMeasuredResultMapper, AqiMeasuredResult> implements AqiMeasuredResultService{

    @Autowired
    private AqiMeasuredResultMapper aqiMeasuredResultMapper;

    @Qualifier("org.xxx.epms.result.feign.InspectorFeign")
    @Autowired
    private InspectorFeign inspectorFeign;

    @Qualifier("org.xxx.epms.result.feign.MonitorFeign")
    @Autowired
    private MonitorFeign monitorFeign;

    @Autowired
    private AqiGradeService aqiGradeService;
    @Autowired
    private GridProvinceMapper gridProvinceMapper;
    @Autowired
    private GridCityMapper gridCityMapper;

    private QueryWrapper<AqiMeasuredResult> getQueryWrapper(AqiMeasuredResultParam aqiMeasuredResultParam){
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(AqiMeasuredResult::getAqimrState, 1);
        if(aqiMeasuredResultParam.getFbId()!= null){
            wrapper.lambda().eq(AqiMeasuredResult::getFbId, aqiMeasuredResultParam.getFbId());
        }
        if(aqiMeasuredResultParam.getCityId() != null){
            wrapper.lambda().eq(AqiMeasuredResult::getCityId, aqiMeasuredResultParam.getCityId());
        }
        if(aqiMeasuredResultParam.getProvinceId() != null) {
            wrapper.lambda().eq(AqiMeasuredResult::getProvinceId, aqiMeasuredResultParam.getProvinceId());
        }
        if(aqiMeasuredResultParam.getAqimrStartDate() != null && aqiMeasuredResultParam.getAqimrEndDate() != null){
            wrapper.lambda().between(AqiMeasuredResult::getAqimrMeasuredTime, aqiMeasuredResultParam.getAqimrStartDate(), aqiMeasuredResultParam.getAqimrEndDate());
        }
        if(aqiMeasuredResultParam.getAqimrId() != null){
            wrapper.lambda().eq(AqiMeasuredResult::getAqimrId, aqiMeasuredResultParam.getAqimrId());
        }
        if(aqiMeasuredResultParam.getAqimrAddress() != null){
            wrapper.lambda().eq(AqiMeasuredResult::getAqimrAddress, aqiMeasuredResultParam.getAqimrAddress());
        }
        if(aqiMeasuredResultParam.getInsTel() != null){
            InspectorDto inspector = inspectorFeign.getInspectorByInsTel(aqiMeasuredResultParam.getInsTel());
            if(inspector != null){
                wrapper.lambda().eq(AqiMeasuredResult::getInsId, inspector.getInsId());
            } else {
                // 如果找不到对应的 inspector，也将条件添加到 wrapper 中
                wrapper.lambda().eq(AqiMeasuredResult::getInsId, 0);
            }
        }
        if(aqiMeasuredResultParam.getInsId() != null){
            wrapper.lambda().eq(AqiMeasuredResult::getInsId, aqiMeasuredResultParam.getInsId());
        }
        return wrapper;
    }

    @Override
    public int createAqiMeasuredResult(AqiMeasuredResult aqiMeasuredResult) {
        if(aqiMeasuredResult.getAqimrCoValue()!=null){
            aqiMeasuredResult.setAqimrCoLevel(
                    aqiGradeService.getAqiGradeByCoValue(aqiMeasuredResult.getAqimrCoValue())
            );
        }
        if(aqiMeasuredResult.getAqimrSo2Value()!=null){
            aqiMeasuredResult.setAqimrSo2Level(
                   aqiGradeService.getAqiGradeBySo2Value(aqiMeasuredResult.getAqimrSo2Value())
            );
        }
        if(aqiMeasuredResult.getAqimrPmValue()!=null){
            aqiMeasuredResult.setAqimrPmLevel(
                    aqiGradeService.getAqiGradeByPmValue(aqiMeasuredResult.getAqimrPmValue())
            );
        }
        if(aqiMeasuredResult.getAqimrCoValue()!=null&&aqiMeasuredResult.getAqimrSo2Value()!=null
                && aqiMeasuredResult.getAqimrPmValue()!=null){
            aqiMeasuredResult.setAqimrState(1);
        }else{
            aqiMeasuredResult.setAqimrState(0);
        }
        return aqiMeasuredResultMapper.insert(aqiMeasuredResult);
    }

    @Override
    public int updateAqiMeasuredResult(AqiMeasuredResult aqiMeasuredResult) {
        if(aqiMeasuredResult.getAqimrCoValue()!=null){
            aqiMeasuredResult.setAqimrCoLevel(
                    aqiGradeService.getAqiGradeByCoValue(aqiMeasuredResult.getAqimrCoValue())
            );
        }
        if(aqiMeasuredResult.getAqimrSo2Value()!=null){
            aqiMeasuredResult.setAqimrSo2Level(
                    aqiGradeService.getAqiGradeBySo2Value(aqiMeasuredResult.getAqimrSo2Value())
            );
        }
        if(aqiMeasuredResult.getAqimrPmValue()!=null){
            aqiMeasuredResult.setAqimrPmLevel(
                    aqiGradeService.getAqiGradeByPmValue(aqiMeasuredResult.getAqimrPmValue())
            );
        }
        if(aqiMeasuredResult.getAqimrCoValue()!=null&&aqiMeasuredResult.getAqimrSo2Value()!=null
                && aqiMeasuredResult.getAqimrPmValue()!=null){
            aqiMeasuredResult.setAqimrState(1);
        }
        return aqiMeasuredResultMapper.updateById(aqiMeasuredResult);
    }

    @Override
    public int getTotalPage(AqiMeasuredResultParam aqiMeasuredResultParam, int pageSize) {
        if(aqiMeasuredResultParam == null){
            long total = aqiMeasuredResultMapper.selectCount(null);
            return (int)total / pageSize + (total % pageSize > 0? 1 : 0);
        }else{
            QueryWrapper<AqiMeasuredResult> wrapper = getQueryWrapper(aqiMeasuredResultParam);
            long total = aqiMeasuredResultMapper.selectCount(wrapper);
            return (int)total / pageSize + (total % pageSize > 0 ? 1 : 0);
        }
    }

    @Override
    public Page<AqiMeasuredResult> getPageList(AqiMeasuredResultParam aqiMeasuredResultParam, int pageSize, int pageNum) {
        if (aqiMeasuredResultParam == null) {
            Page<AqiMeasuredResult> page = new Page<>(pageNum, pageSize);
            return aqiMeasuredResultMapper.selectPage(page, null);
        } else {
            QueryWrapper<AqiMeasuredResult> wrapper = getQueryWrapper(aqiMeasuredResultParam);
            Page<AqiMeasuredResult> page = new Page<>(pageNum, pageSize);
            return aqiMeasuredResultMapper.selectPage(page, wrapper);
        }
    }

    @Override
    public Integer getAqiByAqimrId(Integer aqimrId) {
        AqiMeasuredResult aqiMeasuredResult = aqiMeasuredResultMapper.selectOne(
                new QueryWrapper<AqiMeasuredResult>().eq("aqimr_id", aqimrId));
        if(aqiMeasuredResult.getAqimrState() != 1 ){
            return null;
        }
        return judgeAqi(calculateAqi(aqiMeasuredResult));
    }

    @Override
    public List<ProvinceGroupingDTO> listProvinceGrouping() {
        List<ProvinceGroupingDTO> list = new ArrayList<>();
        List<GridProvince> gridProvinceList = gridProvinceMapper.getProvinceList();
        for (GridProvince gridProvince : gridProvinceList) {
            ProvinceGroupingDTO provinceGroupingDTO = getAqiMeasuredResultByProId(gridProvince.getProvinceId()) !=null ?
                    getAqiMeasuredResultByProId(gridProvince.getProvinceId()) : new ProvinceGroupingDTO();
            provinceGroupingDTO.setProvinceId(gridProvince.getProvinceId());
            provinceGroupingDTO.setProvinceName(gridProvince.getProvinceName());
            provinceGroupingDTO.setProvinceAbbr(gridProvince.getProvinceAbbr());
            list.add(provinceGroupingDTO);
        }
        return list;
    }

    @Override
    public List<AqiTrendDTO> getAqiTrend() {
        List<AqiTrendDTO> trendList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Calendar calendar = Calendar.getInstance();
        for(int i=0;i<12;i++){
            calendar.add(Calendar.MONTH, -1);
            AqiTrendDTO trendDTO = new AqiTrendDTO();
            trendDTO.setMonth(sdf.format(calendar.getTime()));
            List<AqiMeasuredResult> results = findByDate(sdf.format(calendar.getTime()));
            trendDTO.setCount(getAqiByMonth(results));
            trendList.add(trendDTO);
        }
        return trendList;
    }

    @Override
    public List<AqiDistributionDTO> getAqiDistribution() {
        List<AqiMeasuredResult> results = aqiMeasuredResultMapper.selectList(null);
        int[] distributionCounts = countAqiDistribution(results);

        List<AqiDistributionDTO> list = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            AqiDistributionDTO dto = new AqiDistributionDTO();
            dto.setAqiLevel(i + 1);
            dto.setAqiLevelDes(aqiGradeService.getAqiGradeByLevel(i + 1).getAqiLevelDes());
            dto.setAqiDistribution(distributionCounts[i]);
            list.add(dto);
        }
        return list;
    }

    @Override
    public Integer getAqiMeasuredResultCount() {
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.eq("aqimr_state", 1); // 添加检测状态为1的条件
        return Math.toIntExact(aqiMeasuredResultMapper.selectCount(wrapper));
    }

    @Override
    public Integer getAqiMeasuredResultGoodCount() {
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.eq("aqimr_state", 1); // 添加检测状态为1的条件
        List<AqiMeasuredResult> results = aqiMeasuredResultMapper.selectList(wrapper);
        int goodCount = 0;
        for (AqiMeasuredResult aqiMeasuredResult : results) {
            if (calculateAqi(aqiMeasuredResult) <= 100) {
                goodCount += 1;
            }
        }
        return goodCount;
    }

    @Override
    public String getAqiMeasuredResultProvinceCov() {
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.eq("aqimr_state", 1); // 添加检测状态为1的条件
        long provinceNum = gridProvinceMapper.getProvinceCount();
        long provinceCount = aqiMeasuredResultMapper.selectCount(wrapper
                .select("DISTINCT province_id") // 选择不同的省份ID
                .isNotNull("province_id")); // 确保省份ID不为空
        return String.format("%.2f", (double) provinceCount / provinceNum * 100);
    }

    @Override
    public String getAqiMeasuredResultCityCov() {
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.eq("aqimr_state", 1); // 添加检测状态为1的条件
        long cityNum = gridCityMapper.getCityCount();
        long cityCount = aqiMeasuredResultMapper.selectCount(wrapper
                .select("DISTINCT city_id") // 选择不同的城市ID
                .isNotNull("city_id"));// 确保城市ID不为空;
        return String.format("%.2f", (double) cityCount / cityNum * 100);
    }

    @Override
    public AqiMeasuredResultDetailDTO getMeasuredResultByFbId(Integer fbId) {
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(AqiMeasuredResult::getFbId, fbId);
        AqiMeasuredResult aqiMeasuredResult = aqiMeasuredResultMapper.selectOne(wrapper);
        if(aqiMeasuredResult == null){
            return null;
        }
        AqiMeasuredResultDetailDTO dto = new AqiMeasuredResultDetailDTO();
        dto.setAqiMeasuredResult(aqiMeasuredResult);
        InspectorDto inspector = inspectorFeign.getInspectorByInsId(aqiMeasuredResult.getInsId());
        dto.setInspector(inspector);
        if(aqiMeasuredResult.getAqimrState() == 1) {
            dto.setAqiValue(judgeAqi(calculateAqi(aqiMeasuredResult)));
        }
        return dto;
    }

    @Override
    public List<AqiMeasuredResultDetailDTO> getMeasuredResultByInsId(Integer insId) {
        List<AqiMeasuredResultDetailDTO> dtoList = new ArrayList<>();
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(AqiMeasuredResult::getInsId, insId);
        List<AqiMeasuredResult> list = aqiMeasuredResultMapper.selectList(wrapper);
        if(list == null || list.size() == 0){
            return null;
        }
        for(AqiMeasuredResult aqiMeasuredResult : list){
            AqiMeasuredResultDetailDTO dto = new AqiMeasuredResultDetailDTO();
            dto.setAqiMeasuredResult(aqiMeasuredResult);
            InspectorDto inspector = inspectorFeign.getInspectorByInsId(aqiMeasuredResult.getInsId());
            MonitorDto monitor = monitorFeign.getMonitorByMonId(String.valueOf(aqiMeasuredResult.getMonId()));
            dto.setInspector(inspector);
            dto.setMonitor(monitor);
            if(aqiMeasuredResult.getAqimrState() == 1){
                dto.setAqiValue(judgeAqi(calculateAqi(aqiMeasuredResult)));
            }else{
                dto.setAqiValue(null);
            }
            dtoList.add(dto);
        }
        return dtoList;
    }

    public Integer getAqiByMonth(List<AqiMeasuredResult> results){
        Integer monthAqi = 0;
        for(AqiMeasuredResult result : results){
            if(result.getAqimrState() == 1) {
                monthAqi += calculateAqi(result) > 100 ? 1 : 0;
            }
        }
        return monthAqi;
    }

    public List<AqiMeasuredResult> findByDate(String month){
        QueryWrapper<AqiMeasuredResult> wrapper = new QueryWrapper<>();
        wrapper.apply("DATE_FORMAT(aqimr_measured_time, '%Y-%m') = {0}", month);
        return aqiMeasuredResultMapper.selectList(wrapper);
    }

    public ProvinceGroupingDTO getAqiMeasuredResultByProId(Integer provinceId) {
        ProvinceGroupingDTO provinceGroupingDTO = new ProvinceGroupingDTO();
        List<AqiMeasuredResult> list =aqiMeasuredResultMapper.selectList(
                new QueryWrapper<AqiMeasuredResult>().eq("province_id", provinceId));
        Integer coCount = 0,so2Count = 0,pmCount = 0,aqiCount = 0;
        Integer aqiTotal = 0;
        if(list == null || list.size() == 0){
            return null;
        }
        for(AqiMeasuredResult aqiMeasuredResult : list){
            if(aqiMeasuredResult.getAqimrCoLevel()!=null && aqiMeasuredResult.getAqimrCoLevel() > 2){
                coCount+=1;
            }else if(aqiMeasuredResult.getAqimrCoLevel()==null && aqiMeasuredResult.getAqimrCoValue()!=null){
                int coLevel = aqiGradeService.getAqiGradeByCoValue(aqiMeasuredResult.getAqimrCoValue());
                if(coLevel > 2){
                    coCount+=1;
                }
            }
            if(aqiMeasuredResult.getAqimrSo2Level()!=null && aqiMeasuredResult.getAqimrSo2Level() > 2){
                so2Count+=1;
            }else if(aqiMeasuredResult.getAqimrSo2Level()==null && aqiMeasuredResult.getAqimrSo2Value()!=null){
                int so2Level = aqiGradeService.getAqiGradeBySo2Value(aqiMeasuredResult.getAqimrSo2Value());
                if(so2Level > 2){
                    so2Count+=1;
                }
            }
            if(aqiMeasuredResult.getAqimrPmLevel()!=null && aqiMeasuredResult.getAqimrPmLevel() > 2){
                pmCount+=1;
            } else if (aqiMeasuredResult.getAqimrPmLevel()==null && aqiMeasuredResult.getAqimrPmValue()!=null) {
                int pmLevel = aqiGradeService.getAqiGradeByPmValue(aqiMeasuredResult.getAqimrPmValue());
                if(pmLevel > 2){
                    pmCount+=1;
                }
            }

            if (aqiMeasuredResult.getAqimrCoValue()!=null&&aqiMeasuredResult.getAqimrSo2Value()!=null&&aqiMeasuredResult.getAqimrPmValue()!=null)
            {
                int aqiValue = calculateAqi(aqiMeasuredResult);
                aqiTotal+=aqiValue;
                if(aqiValue > 100){
                    aqiCount+=1;
                }else{
                    aqiCount+=0;
                }
            }else{
                aqiCount+=0;
            }
        }
        provinceGroupingDTO.setAqiLevel(judgeAqi(aqiTotal/list.size()));
        provinceGroupingDTO.setProvinceId(provinceId);
        provinceGroupingDTO.setCoCount(coCount);
        provinceGroupingDTO.setSo2Count(so2Count);
        provinceGroupingDTO.setPmCount(pmCount);
        provinceGroupingDTO.setAqiCount(aqiCount);
        return  provinceGroupingDTO;
    }

    // AQI计算方法
    public int calculateAqi(AqiMeasuredResult aqiMeasuredResult) {
        int coValue = aqiMeasuredResult.getAqimrCoValue();
        int so2Value = aqiMeasuredResult.getAqimrSo2Value();
        int pmValue = aqiMeasuredResult.getAqimrPmValue();

        //再次判断这几个值不为空
        if (Objects.isNull(coValue) || Objects.isNull(so2Value) || Objects.isNull(pmValue)) {
            return 0; // or return a default value
        }

        int coLevel = aqiMeasuredResult.getAqimrCoLevel() !=null ?
                aqiMeasuredResult.getAqimrCoLevel():aqiGradeService.getAqiGradeByCoValue(coValue);
        int so2Level = aqiMeasuredResult.getAqimrSo2Level() !=null ?
                aqiMeasuredResult.getAqimrSo2Level():aqiGradeService.getAqiGradeBySo2Value(so2Value);
        int pmLevel = aqiMeasuredResult.getAqimrPmLevel() !=null ?
                aqiMeasuredResult.getAqimrPmLevel():aqiGradeService.getAqiGradeByPmValue(pmValue);

        // 获取各污染物的等级范围
        int[] coRange = listLevel(coLevel);
        int[] so2Range = listLevel(so2Level);
        int[] pmRange = listLevel(pmLevel);

        //获得到对应等级的取值范围
        AqiGrade coGrade = aqiGradeService.getAqiGradeByLevel(coLevel);
        AqiGrade so2Grade = aqiGradeService.getAqiGradeByLevel(so2Level);
        AqiGrade pmGrade = aqiGradeService.getAqiGradeByLevel(pmLevel);


        // 计算AQI
        int coAqi = calculateAqiForPollutant(coValue,coGrade.getAqiCoMax(),coGrade.getAqiCoMin(),coRange[0],coRange[1]);
        int so2Aqi = calculateAqiForPollutant(so2Value,so2Grade.getAqiSo2Max(),so2Grade.getAqiSo2Min(),so2Range[0],so2Range[1]);
        int pmAqi = calculateAqiForPollutant(pmValue,pmGrade.getAqiPmMax(),pmGrade.getAqiPmMin(),pmRange[0],pmRange[1]);
        return  Math.max(coAqi,Math.max(so2Aqi,pmAqi));
    }

    //aqi计算公式
    private int calculateAqiForPollutant(double pollutantValue, double breakpointHigher, double breakpointLower, double aqilower, double aqihigher) {
        return (int) Math.round(aqilower + (aqihigher - aqilower) * (pollutantValue - breakpointLower) / (breakpointHigher-breakpointLower));
    }

    //aqi各等级范围
    private int[] listLevel(int level){
        int[] levels = new int[2];
        switch (level){
            case 1:
                levels[0] = 0;
                levels[1] = 50;
                break;
            case 2:
                levels[0] = 51;
                levels[1] = 100;
                break;
            case 3:
                levels[0] = 101;
                levels[1] = 150;
                break;
            case 4:
                levels[0] = 151;
                levels[1] = 200;
                break;
            case 5:
                levels[0] = 201;
                levels[1] = 300;
                break;
            case 6:
                levels[0] = 301;
                levels[1] = 400;
                break;
            default:
                throw new IllegalArgumentException("Invalid level: " + level);
        }
        return levels;
    }

    //根据数据范围判断aqi等级
    public int judgeAqi(int aqiValue) {
        return IntStream.rangeClosed(1, 6)
                .filter(level -> aqiValue >= listLevel(level)[0] && aqiValue <= listLevel(level)[1])
                .findFirst()
                .orElse(6); // 未找到相关AQI等级，默认6
    }

    //统计空气质量指数等级分布数组
    public int[] countAqiDistribution(List<AqiMeasuredResult> results) {
        int[] distributionCounts = new int[6];
        results.stream()
                .filter(r -> r.getAqimrCoValue() != null && r.getAqimrSo2Value() != null && r.getAqimrPmValue() != null)
                .mapToInt(this::calculateAqi)
                .forEach(aqiValue -> {
                    int level = judgeAqi(aqiValue);
                    if (level >= 1 && level <= 6) {
                        distributionCounts[level - 1]++;
                    }
                });
        return distributionCounts;
    }
}
